package com.atstudent.gmall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.atstudent.gmall.cart.entity.CartItem;
import com.atstudent.gmall.cart.service.CartService;
import com.atstudent.gmall.common.constant.GmallConstant;
import com.atstudent.gmall.common.execption.GmallException;
import com.atstudent.gmall.common.feign.interceptor.AuthUserInfo;
import com.atstudent.gmall.common.feign.product.SkuFeignClient;
import com.atstudent.gmall.common.feign.util.AuthUserInfoUtils;
import com.atstudent.gmall.common.result.ResultCodeEnum;
import com.atstudent.gmall.product.entity.SkuInfo;
import com.atstudent.gmall.user.entity.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author 薛有朋
 * @CreatDate 2025/4/18 20:57
 **/
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate<String , String> redisTemplate;

    @Autowired
    private SkuFeignClient skuFeignClient;

    @Override
    public List<CartItem> findAllCartItem() {
        //查看用户是否登录
        AuthUserInfo authUserInfo = AuthUserInfoUtils.getAuthUserInfo();
        String userId = authUserInfo.getUserId();
        if (!StringUtils.isEmpty(userId)) { //用户已登录 需要合并购物项
            //获取用户购物车的数据key
            String userCartRediskey = GmallConstant.REDIS_CART_PRE + authUserInfo.getUserId();
            //获取临时用户购物车的数据key
            String userTempCartRediskey = GmallConstant.REDIS_CART_PRE + authUserInfo.getUserTempId();
            
            //获取临时用户购物车数据项
            List<CartItem> userTempCartItemList = redisTemplate.opsForHash().values(userTempCartRediskey).stream().map(obj -> {
                String cartItemTempJSON = obj.toString();
                CartItem cartItemTemp = JSON.parseObject(cartItemTempJSON, CartItem.class);
                return cartItemTemp;
            }).collect(Collectors.toList());
            //获取临时购物车数据项的所有skuId，为去重做准备
            List<Long> userTempCartSkuIds = userTempCartItemList.stream().map(userTempCartItem -> {
                Long skuId = userTempCartItem.getSkuId();
                return skuId;
            }).collect(Collectors.toList());

            //获取登录用户的购物车数据项的所有skuId
            List<Long> userCartSkuIds = redisTemplate.opsForHash().values(userCartRediskey).stream().map(obj -> {
                String cartItemJSON = obj.toString();
                CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);
                Long skuId = cartItem.getSkuId();
                return skuId;
            }).collect(Collectors.toList());

            //对购物车和临时购物车的skuId进行合并集合并去重
            List<Long> collect = Stream.concat(userCartSkuIds.stream(), userTempCartSkuIds.stream()).distinct().collect(Collectors.toList());

            //对去重后的购物项数量进行校验
            if (collect.size() > 3){
                redisTemplate.delete(userTempCartRediskey);
                throw new GmallException(ResultCodeEnum.CART_ITEM_NUMBER_ERROR) ;
            }

            //遍历临时购物车数据项，并判断在用户购物车中是否存在此购物项
            for (CartItem userTempCartItem : userTempCartItemList) {
                //拿到每个临时购物车数据项的skuID
                Long SkuIdTemp = userTempCartItem.getSkuId();
                //判断这个skuId在用户购物车中是否存在
                Boolean hasKey = redisTemplate.opsForHash().hasKey(userCartRediskey, String.valueOf(SkuIdTemp));

                if (hasKey){ //如果存在 则对此购物项的购买数量进行相加
                    //先拿到此临时skuId对应的用户购物车中的数据
                    String userCartItemJSON = redisTemplate.opsForHash().get(userCartRediskey, String.valueOf(SkuIdTemp)).toString();
                    CartItem userCartItem = JSON.parseObject(userCartItemJSON, CartItem.class);
                    userCartItem.setSkuNum(userCartItem.getSkuNum() + userTempCartItem.getSkuNum());
                    //拿到skuNum 对他的数量进行限制处理
                    if (userCartItem.getSkuNum() > 10){
                        userCartItem.setSkuNum(10);
                        throw new GmallException(ResultCodeEnum.CART_ITEM_NUMBERS_ERROR);
                    }
                    //处理完skuNum之后，重新添加到Redis中
                    redisTemplate.opsForHash().put(userCartRediskey , String.valueOf(SkuIdTemp) , JSON.toJSONString(userCartItem));
                }else { //如果不存在 则直接添加到用户购物车中 key用的是真实购物车的 小key是临时购物车的 因为是把临时购物车中的数据添加进去
                    redisTemplate.opsForHash().put(userCartRediskey , String.valueOf(SkuIdTemp) , JSON.toJSONString(userTempCartItem));
                }
            }

            //删除临时购物车
            redisTemplate.delete(userTempCartRediskey);

            //合并购物车结束之后 把用户购物车数据进行返回
            List<CartItem> cartItemList = redisTemplate.opsForHash().values(userCartRediskey).stream().map(obj -> {
                        String cartItemJSON = obj.toString();
                        CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);
                        //更新价格
                        updateSkuPrice(cartItem , userCartRediskey);
                        return cartItem;
                    }).sorted((c1, c2) -> (int) (c1.getCreateTime().getTime() - c2.getCreateTime().getTime()))
                      .collect(Collectors.toList());

            return cartItemList;
        } else { //用户未登录
            //拿到Redis数据key
            String redisKey = buildRedisKey();
            List<CartItem> cartItemList = redisTemplate.opsForHash().values(redisKey).stream().map(obj -> {
                String cartItemJSON = obj.toString();
                CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);

                //更新价格
                updateSkuPrice(cartItem , redisKey);

                return cartItem;
            }).sorted((c1 , c2) -> (int) (c1.getCreateTime().getTime() - c2.getCreateTime().getTime()))
              .collect(Collectors.toList());
            return cartItemList;
        }
    }

    /**
     * 更新Redis中商品的价格
     * @Author 薛有朋
     * @Date 2025/4/30 18:54
     **/
    private void updateSkuPrice(CartItem cartItem, String redisKey) {
        //远程调用service-product微服务的查询商品详情接口
        SkuInfo skuInfo = skuFeignClient.findSkuInfoBySkuId(cartItem.getSkuId()).getData();
        cartItem.setSkuPrice(skuInfo.getPrice());
        //重新写入到Redis中
        redisTemplate.opsForHash().put(redisKey , String.valueOf(cartItem.getSkuId()) , JSON.toJSONString(cartItem));
    }

    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        //拿到Redis数据key
        String redisKey = buildRedisKey();
        String cartItemJSON = redisTemplate.opsForHash().get(redisKey, String.valueOf(skuId)).toString();
        CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);
        cartItem.setSkuNum(cartItem.getSkuNum() + skuNum);
        if (cartItem.getSkuNum() > 10){
            cartItem.setSkuNum(10);
            throw new GmallException(ResultCodeEnum.CART_ITEM_NUMBERS_ERROR);
        }
        //重新添加到Redis中
        redisTemplate.opsForHash().put(redisKey , String.valueOf(skuId) , JSON.toJSONString(cartItem));
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        //拿到Redis数据key
        String redisKey = buildRedisKey();
        String cartItemJSON = redisTemplate.opsForHash().get(redisKey, String.valueOf(skuId)).toString();
        CartItem cartItem = JSON.parseObject(cartItemJSON, CartItem.class);
        cartItem.setIsChecked(isChecked);
        //重新添加到Redis中
        redisTemplate.opsForHash().put(redisKey , String.valueOf(skuId) , JSON.toJSONString(cartItem));
    }

    @Override
    public void deleteCart(Long skuId) {
        //拿到Redis数据key
        String redisKey = buildRedisKey();
        //删除Redis中的此条数据
        redisTemplate.opsForHash().delete(redisKey , String.valueOf(skuId));
    }

    private String buildRedisKey() {
        //封装了用户的id和临时用户的id
        AuthUserInfo authUserInfo = AuthUserInfoUtils.getAuthUserInfo();
        if (authUserInfo != null) {
            String userId = authUserInfo.getUserId();
            String userTempId = authUserInfo.getUserTempId();
            if (!StringUtils.isEmpty(userId)) {
                return GmallConstant.REDIS_CART_PRE + userId;
            } else {
                return GmallConstant.REDIS_CART_PRE + userTempId;
            }
        }else {
            return null;
        }
    }

}
